# Copyright 2021 Erfan Abdi
# SPDX-License-Identifier: GPL-3.0-or-later
import glob
import logging
import os
import threading
import tools.config
import tools.helpers.net
from pathlib import Path
from tools.interfaces import IUserMonitor
from tools.interfaces import IPlatform
from gi.repository import GLib

stopping = False

def start(args, session, unlocked_cb=None):
    waydroid_data = session["waydroid_data"]
    apps_dir = session["xdg_data_home"] + "/applications/"

    system_apps = [
        "com.android.calculator2",
        "com.android.camera2",
        "com.android.contacts",
        "com.android.deskclock",
        "com.android.documentsui",
        "com.android.email",
        "com.android.gallery3d",
        "com.android.inputmethod.latin",
        "com.android.settings",
        "com.google.android.gms",
        "org.lineageos.aperture",
        "org.lineageos.eleven",
        "org.lineageos.etar",
        "org.lineageos.jelly",
        "org.lineageos.recorder"
    ]


    def prepend_list(old_list, new_list):
        for s in reversed(new_list):
            if s not in old_list:
                old_list.insert(0, s)

    def glib_key_file_get_string_list(key_file, group, key):
        try:
            return key_file.get_string_list(group, key)
        except:
            return []

    def glib_key_file_prepend_string_list(key_file, group, key, new_list):
        lst = glib_key_file_get_string_list(key_file, group, key)
        prepend_list(lst, new_list)
        key_file.set_string_list(group, key, lst)

    def glib_key_file_has_value(key_file, group, key):
        try:
            key_file.get_value(group, key)
            return True
        except:
            return False

    # Migrate waydroid user configs after upgrade
    def user_migration():
        apps_dir = session["xdg_data_home"] + "/applications/"
        state_dir = session["waydroid_user_state"]
        if not any(glob.iglob(f'{apps_dir}/waydroid.*.desktop')):
            # first ever run, no need to migrate
            return

        if not os.path.exists(os.path.join(state_dir, ".migrated-main-desktop-file")):
            Path(os.path.join(apps_dir, "Waydroid.desktop")).unlink(missing_ok=True)
            Path(os.path.join(state_dir, ".migrated-main-desktop-file")).touch()

        if not os.path.exists(os.path.join(state_dir, ".migrated-app-settings-desktop-action")):
            for app in glob.iglob(f'{apps_dir}/waydroid.*.desktop'):
                try:
                    desktop_file = GLib.KeyFile()
                    flags = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
                    desktop_file.load_from_file(app, flags)
                    try:
                        desktop_file.remove_group("Desktop Action app_settings")
                    except:
                        pass
                    try:
                        actions = glib_key_file_get_string_list(desktop_file, "Desktop Entry", "Actions")
                        actions.remove("app_settings")
                        desktop_file.set_string_list("Desktop Entry", "Actions", actions)
                    except:
                        pass
                    desktop_file.save_to_file(app)
                except:
                    continue
            Path(os.path.join(state_dir, ".migrated-app-settings-desktop-action")).touch()

    # Creates, deletes, or updates desktop file
    def updateDesktopFile(appInfo):
        if appInfo is None:
            return

        showApp = False
        for cat in appInfo["categories"]:
            if cat.strip() == "android.intent.category.LAUNCHER":
                showApp = True
        if not showApp:
            try:
                os.remove(desktop_file_path)
            except:
                pass

        packageName = appInfo["packageName"]

        desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
        desktop_file = GLib.KeyFile()
        try:
            flags = GLib.KeyFileFlags.KEEP_COMMENTS | GLib.KeyFileFlags.KEEP_TRANSLATIONS
            desktop_file.load_from_file(desktop_file_path, flags)
        except:
            pass

        desktop_file.set_string("Desktop Entry", "Type", "Application")
        desktop_file.set_string("Desktop Entry", "Name", appInfo["name"])
        desktop_file.set_string("Desktop Entry", "Exec", f"waydroid app launch {packageName}")
        desktop_file.set_string("Desktop Entry", "Icon", f"{waydroid_data}/icons/{packageName}.png")
        glib_key_file_prepend_string_list(desktop_file, "Desktop Entry", "Categories", ["X-WayDroid-App"])
        desktop_file.set_string_list("Desktop Entry", "X-Purism-FormFactor", ["Workstation", "Mobile"])
        glib_key_file_prepend_string_list(desktop_file, "Desktop Entry", "Actions", ["app-settings"])
        if packageName in system_apps and not glib_key_file_has_value(desktop_file, "Desktop Entry", "NoDisplay"):
            desktop_file.set_boolean("Desktop Entry", "NoDisplay", True)

        desktop_file.set_string("Desktop Action app-settings", "Name", "App Settings")
        desktop_file.set_string("Desktop Action app-settings", "Exec", f"waydroid app intent android.settings.APPLICATION_DETAILS_SETTINGS package:{packageName}")
        desktop_file.set_string("Desktop Action app-settings", "Icon", f"{waydroid_data}/icons/com.android.settings.png")

        desktop_file.save_to_file(desktop_file_path)


    def userUnlocked(uid):
        cfg = tools.config.load(args)
        logging.info("Android with user {} is ready".format(uid))

        user_migration()

        if cfg["waydroid"]["auto_adb"] == "True":
            try:
                tools.helpers.net.adb_connect(args)
            except:
                pass

        platformService = IPlatform.get_service(args)
        if platformService:
            if not os.path.exists(apps_dir):
                os.mkdir(apps_dir, 0o700)
            appsList = platformService.getAppsInfo()
            for app in appsList:
                updateDesktopFile(app)
            for existing in glob.iglob(f'{apps_dir}/waydroid.*.desktop'):
                if os.path.basename(existing) not in map(lambda appInfo: f"waydroid.{appInfo['packageName']}.desktop", appsList):
                    os.remove(existing)
        if unlocked_cb:
            unlocked_cb()

    def packageStateChanged(mode, packageName, uid):
        platformService = IPlatform.get_service(args)
        if platformService:
            desktop_file_path = apps_dir + "/waydroid." + packageName + ".desktop"
            if mode == IUserMonitor.PACKAGE_REMOVED:
                try:
                    os.remove(desktop_file_path)
                except:
                    pass
            else:
                appInfo = platformService.getAppInfo(packageName)
                updateDesktopFile(appInfo)

    def service_thread():
        while not stopping:
            IUserMonitor.add_service(args, userUnlocked, packageStateChanged)

    global stopping
    stopping = False
    args.user_manager = threading.Thread(target=service_thread)
    args.user_manager.start()

def stop(args):
    global stopping
    stopping = True
    try:
        if args.userMonitorLoop:
            args.userMonitorLoop.quit()
    except AttributeError:
        logging.debug("UserMonitor service is not even started")
